/**
 * Copyright (c) 2016-present, lovebing.org.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package org.lovebing.reactnative.baidumap.module;

import android.Manifest;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.LocationListener;
import android.util.Log;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.LocationClientOption.LocationMode;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.search.core.PoiInfo;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.geocode.GeoCodeOption;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.GeoCoder;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
import com.baidu.mapapi.search.sug.OnGetSuggestionResultListener;
import com.baidu.mapapi.search.sug.SuggestionResult;
import com.baidu.mapapi.search.sug.SuggestionSearch;//新增
import com.baidu.mapapi.search.sug.SuggestionSearchOption;
import com.baidu.mapapi.utils.CoordinateConverter;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.PermissionListener;

import org.lovebing.reactnative.baidumap.support.AppUtils;

import java.util.List;

import javax.annotation.Nullable;

/**
 * Created by lovebing on 2016/10/28.
 */
public class GeolocationModule extends BaseModule
        implements OnGetGeoCoderResultListener, OnGetSuggestionResultListener {

    private LocationClient locationClient;
    private MyLocationListener mLocationListener = new MyLocationListener();
    private static GeoCoder geoCoder;
    private volatile boolean locating = false;
    private volatile boolean locateOnce = false;
    private static SuggestionSearch sugSearch;//新增

    public GeolocationModule(ReactApplicationContext reactContext) {
        super(reactContext);
        context = reactContext;
    }

    public String getName() {
        return "BaiduGeolocationModule";
    }
    private boolean initLocationClient( String coorType) {

        LocationClientOption option = new LocationClientOption();
        option.setLocationMode(LocationMode.Hight_Accuracy);
        if (coorType != null){
            option.setCoorType(coorType);
        }

        option.setIsNeedAddress(true);
        option.setIsNeedAltitude(true);
        option.setIsNeedLocationDescribe(true);
        option.setOpenGps(true);
        if (locationClient == null){
            try {
                locationClient = new LocationClient(getReactApplicationContext().getApplicationContext());
            } catch (Exception e) {
                Log.e("aaaa",e.getMessage().toString());
//            e.printStackTrace();
            }
            locationClient.registerLocationListener(mLocationListener);
        }

        locationClient.setLocOption(option);
        Log.i("locationClient", "locationClient");
        Boolean isLocation = false;
        try {
            isLocation = AppUtils.checkPermission(getCurrentActivity(), Manifest.permission.ACCESS_FINE_LOCATION, new PermissionListener() {
                @Override
                public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
                    switch (requestCode) {
                        case 1: {
                            // If request is cancelled, the result arrays are empty.
                            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//                                    Toast.makeText(getCurrentActivity().getApplicationContext(), "我是if", Toast.LENGTH_LONG).show();
                                //用户选择了授权
                                locationClient.start();
                            } else {
                                //用户选择了拒绝
//                                    Toast.makeText(getCurrentActivity().getApplicationContext(), "我是else", Toast.LENGTH_LONG).show();
                            }
                            return true;
                        }
                    }
                    return false;
                }
            } );
        }catch (Exception e){
            isLocation = false;
        }

        return isLocation;

    }
    protected SuggestionSearch getSuggestionSearch() {
        //新增
        if(sugSearch != null) {
            sugSearch.destroy();
        }
        sugSearch = SuggestionSearch.newInstance();
        sugSearch.setOnGetSuggestionResultListener(this);
        return sugSearch;
    }
    /**
     *
     * @return
     */
    protected GeoCoder getGeoCoder() {
        if(geoCoder != null) {
            geoCoder.destroy();
        }
        geoCoder = GeoCoder.newInstance();//新增
        geoCoder.setOnGetGeoCodeResultListener(this);
        return geoCoder;
    }

    /**
     *
     * @param sourceLatLng
     * @return
     */
    protected LatLng getBaiduCoorFromGPSCoor(LatLng sourceLatLng) {
        CoordinateConverter converter = new CoordinateConverter();
        converter.from(CoordinateConverter.CoordType.GPS);
        converter.coord(sourceLatLng);
        LatLng desLatLng = converter.convert();
        return desLatLng;

    }

    @ReactMethod
    public void convertGPSCoor(double lat, double lng, Promise promise) {
        Log.i("convertGPSCoor", "convertGPSCoor");
        LatLng latLng = getBaiduCoorFromGPSCoor(new LatLng(lat, lng));
        WritableMap map = Arguments.createMap();
        map.putDouble("latitude", latLng.latitude);
        map.putDouble("longitude", latLng.longitude);
        promise.resolve(map);
    }

    @ReactMethod
    public void getCurrentPosition( String coorType) throws Exception {
        locateOnce = true;
        if (locating) {
            //已经在定位了
            return;
        }

        Boolean isb = initLocationClient(coorType);
        Log.i("getCurrentPosition", "getCurrentPosition");
        if (isb) {
            locationClient.start();
        }
    }

    @ReactMethod
    public void startLocating( String coorType) throws Exception {
        if (locating ) {
            //已经开始持续定位了。
            return;
        }
        locating = true;
        Boolean isb = initLocationClient(coorType);
        if (isb){
            locationClient.start();
        }

    }

    @ReactMethod
    public void stopLocating() {
        locating = false;
        if (locationClient != null) {
            locationClient.stop();
            locationClient = null;
        }
    }

    @ReactMethod
    public void geocode(String city, String addr) {
        getGeoCoder().geocode(new GeoCodeOption()
                .city(city).address(addr));
    }
    @ReactMethod
    public void SuggestionSearch(String city, String addr) {
            //新增
        getSuggestionSearch().requestSuggestion((new SuggestionSearchOption())
                .keyword(addr)
                .city(city));

    }
    @ReactMethod
    public void reverseGeoCode(double lat, double lng) {
        getGeoCoder().reverseGeoCode(new ReverseGeoCodeOption()
                .location(new LatLng(lat, lng)));
    }

    @ReactMethod
    public void reverseGeoCodeGPS(double lat, double lng) {
        getGeoCoder().reverseGeoCode(new ReverseGeoCodeOption()
                .location(getBaiduCoorFromGPSCoor(new LatLng(lat, lng))));
    }
    class MyLocationListener extends BDAbstractLocationListener {
        @Override
        public void onReceiveLocation(final BDLocation bdLocation) {


            WritableMap params = Arguments.createMap();
            if (bdLocation != null){
                params.putDouble("latitude", bdLocation.getLatitude());
                params.putDouble("longitude", bdLocation.getLongitude());
                params.putDouble("speed", bdLocation.getSpeed());
                params.putDouble("direction", bdLocation.getDirection());
                params.putDouble("altitude", bdLocation.getAltitude());
                params.putDouble("radius", bdLocation.getRadius());
                params.putString("address", bdLocation.getAddrStr());
                params.putString("countryCode", bdLocation.getCountryCode());
                params.putString("country", bdLocation.getCountry());
                params.putString("province", bdLocation.getProvince());
                params.putString("cityCode", bdLocation.getCityCode());
                params.putString("city", bdLocation.getCity());
                params.putString("district", bdLocation.getDistrict());
                params.putString("street", bdLocation.getStreet());
                params.putString("streetNumber", bdLocation.getStreetNumber());
                params.putString("buildingId", bdLocation.getBuildingID());
                params.putString("buildingName", bdLocation.getBuildingName());
            }

            Log.i("onReceiveLocation", "onGetCurrentLocationPosition");
            if (locateOnce) {
                locateOnce = false;
                //一次定位
                sendEvent("onGetCurrentLocationPosition", params);
                if (locating == false) {
                    //没有持续定位，因此一次定位后直接暂停
                    stopLocating();
                }
            }
            if (locating) {
                //持续定位
                sendEvent("onLocationUpdate", params);
            }

//            if (locateOnce) {
//                locating = false;
//                sendEvent("onGetCurrentLocationPosition", params);
//                locationClient.stop();
//                locationClient = null;
//            } else {
//                sendEvent("onLocationUpdate", params);
//            }
        }
    }
//
//    public void onReceiveLocation(BDLocation bdLocation) {
//        WritableMap params = Arguments.createMap();
//        params.putDouble("latitude", bdLocation.getLatitude());
//        params.putDouble("longitude", bdLocation.getLongitude());
//        params.putDouble("speed", bdLocation.getSpeed());
//        params.putDouble("direction", bdLocation.getDirection());
//        params.putDouble("altitude", bdLocation.getAltitude());
//        params.putDouble("radius", bdLocation.getRadius());
//        params.putString("address", bdLocation.getAddrStr());
//        params.putString("countryCode", bdLocation.getCountryCode());
//        params.putString("country", bdLocation.getCountry());
//        params.putString("province", bdLocation.getProvince());
//        params.putString("cityCode", bdLocation.getCityCode());
//        params.putString("city", bdLocation.getCity());
//        params.putString("district", bdLocation.getDistrict());
//        params.putString("street", bdLocation.getStreet());
//        params.putString("streetNumber", bdLocation.getStreetNumber());
//        params.putString("buildingId", bdLocation.getBuildingID());
//        params.putString("buildingName", bdLocation.getBuildingName());
//        Log.i("onReceiveLocation", "onGetCurrentLocationPosition");
//
//        if (locateOnce) {
//            locating = false;
//            sendEvent("onGetCurrentLocationPosition", params);
//            locationClient.stop();
//            locationClient = null;
//        } else {
//            sendEvent("onLocationUpdate", params);
//        }
//    }

    @Override
    public void onGetGeoCodeResult(GeoCodeResult result) {
        WritableMap params = Arguments.createMap();
        if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
            params.putInt("errcode", -1);
        }
        else {
            params.putDouble("latitude",  result.getLocation().latitude);
            params.putDouble("longitude",  result.getLocation().longitude);
        }
        sendEvent("onGetGeoCodeResult", params);
    }

    @Override
    public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
        WritableMap params = Arguments.createMap();
        if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
            params.putInt("errcode", -1);
        }
        else {
            ReverseGeoCodeResult.AddressComponent addressComponent = result.getAddressDetail();
            params.putString("address", result.getAddress());
            params.putString("province", addressComponent.province);
            params.putString("city", addressComponent.city);
            params.putString("district", addressComponent.district);
            params.putString("street", addressComponent.street);
            params.putString("streetNumber", addressComponent.streetNumber);
            List<PoiInfo> array =result.getPoiList();
            WritableArray modules = Arguments.createArray();
            if (array != null && array.size() != 0){
                for (PoiInfo item : array) {
                    if (item.location == null){
                        continue;
                    }
                    WritableMap dic = Arguments.createMap();
                    dic.putString("street",item.name);
                    dic.putString("city",addressComponent.city);
                    dic.putString("addr",item.address);
                    dic.putString("district",addressComponent.district);
                    dic.putString("cid",item.uid);
                    dic.putString("doorplate",item.address);
                    WritableMap dic2 = Arguments.createMap();
                    dic2.putDouble("lat",item.location.latitude);
                    dic2.putDouble("lng",item.location.longitude);
                    dic.putMap("location",dic2);
                    modules.pushMap(dic);
                }
            }

            params.putArray("list",modules);
        }
        sendEvent("onGetReverseGeoCodeResult", params);
    }
    @Override
    public void onGetSuggestionResult(SuggestionResult res) {
    //热词搜索
        System.out.println("dasd"+res.getAllSuggestions());
        if (res == null || res.getAllSuggestions() == null) {
            return;
            //未找到相关结果
        }
        List<SuggestionResult.SuggestionInfo> array =res.getAllSuggestions();
        WritableArray modules = Arguments.createArray();
        if (array != null && array.size() != 0) {
            for (SuggestionResult.SuggestionInfo item : array) {
                if (item.pt == null){
                    continue;
                }
                WritableMap dic = Arguments.createMap();
                dic.putString("street",item.key);
                dic.putString("city",item.city);
                dic.putString("addr","");
                dic.putString("district",item.district);
                dic.putString("cid",item.uid);
                dic.putString("doorplate","");
                WritableMap dic2 = Arguments.createMap();
                dic2.putDouble("lat",item.pt.latitude);
                dic2.putDouble("lng",item.pt.longitude);
                dic.putMap("location",dic2);
                modules.pushMap(dic);
            }
        }
        WritableMap pream = Arguments.createMap();
        pream.putArray("data",modules);
        sendEvent("onGetSuggestionResult", pream);
        //获取在线建议检索结果
    }
    @ReactMethod
    public void addListener(String eventName) {
        // Set up any upstream listeners or background tasks as necessary
    }
    @ReactMethod
    public void removeListeners(Integer count) {
        // Remove upstream listeners, stop unnecessary background tasks
    }
}
